/*
* loop.c - Main Loop Relocate
* Copyright 2006-2008 OpenWii (admin@openwii.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* Version 2.4 by Andii
*/

#include "../common/drive.h"
#include "mn10200-wii.h"

const unsigned char regData[3][10] =
{
	{0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80},	// JAP_R 0x00 is JAP
	{0x10, 0x00, 0x00, 0x00, 0x10, 0xE0, 0x04, 0x00, 0x00, 0x00},	// USA_R 0x01 is USA
	{0x00, 0x80, 0x80, 0x06, 0x03, 0x03, 0x04, 0x03, 0x07, 0x00}	// PAL_R 0x02 is PAL
};

unsigned char backup;
unsigned int update_count;

void startBigLoop(void) __attribute__ ((noreturn));
void startBigLoop(void)
{
	update_count = 0;

	goto OpenWiiEntry;
	while (42)
	{
		if ((backup == 1) && (loginStatus >= 0xf4))
		{
			backup = 2;
			if ((ourSpeed & SPEED_MASK) == CONFIG_SLOW_SPEED)
			{
				speedFlag = 0x3000;	// speed 3x - Wario seems to not studder ;)
			}
			else
			{
				speedFlag = 0xbd01;	// speed 6x (default)
			}
		}

		if ((loc_8336 == 0) || (loc_85b8 != 0))
		{
			cmd0Flags = 0;
			asm("mov _cmd0Flags, a0");
			taskWait(0x01, (void*)0xffff, 0x01);

			// region freeness is here
			if ((ourRegion < CONFIG_res_R) &&
				(cmdDiBytes[0] == DI_READSECTOR) &&
				(cmdDiBytes[4] == 0x00))
			{
				if ((cmdDiBytes[5] == 0x01) &&
					(cmdDiBytes[6] == 0x38) &&
					(cmdDiBytes[7] == 0x00))
				{	// wii region sector
					register unsigned int region = ourRegion;
					register unsigned char* p_mem asm("a0");	// code size optimisation
					memmap = (void*)0x21d3c0;
					if (backup == 2)
					{
						p_mem = membuf + 0x0f;
					}
					else
					{
						p_mem = membuf + 0x09;
					}
					if (*p_mem != region)
					{
						*p_mem = region;
						asm("add 0x0d, a0");
						memcpy(sizeof(regData[0]), &regData[0][(region << 3) + (region << 1)]);
					}
				}
				if ((cmdDiBytes[5] == 0x00) &&
					(cmdDiBytes[6] == 0x01) &&
					(cmdDiBytes[7] == 0x10))
				{	// gc region sector
					register unsigned int region = ourRegion;
					memmap = (void*)0x20f200;
					if (backup == 2)
					{
						switch (region)
						{
							case CONFIG_USA_R:
								membuf[0x0f] = 0x45;	// USA
							break;
							case CONFIG_PAL_R:
								membuf[0x0f] = 0x50;	// PAL
							break;
							case CONFIG_JAP_R:
								membuf[0x0f] = 0x4a;	// JAP
							break;
						}
						membuf[0x0467] = region;
					}
					else
					{	// original GC Game Import offsets for region are a bit off
						membuf[0x0461] = region;
					}
				}
				memmap = 0;
			}

			// copy firmware to buffer for bootloader
			if (cmdDiBytes[0] == DI_SETUPDATEDATA)
			{
				register unsigned int count = update_count; // help the stupid compiler saving code size
				flashUpdate[count] = cmdDiBytes[3];
				update_count = count + 1;
			}
			// check for a openwii setup command
			if (cmdDiBytes[0] == DI_CONFIGCOMMAND)
			{
				configCommandL = cmdDiBytes[3];
				configCommandH = CONFIG_MAGIC;
			}
			if (backup == 2)
			{
				if (mediaFlagL != 0x38)
				{
					mediaFlagL = 0x38;
				}
				else
				{	// SMG fix
					if (cmdDiBytes[0] == DI_REPORTDISCKEY)
					{
						mediaFlagL = 0x80;
					}
				}
			}

OpenWiiEntry:
			if ((cmd0Flags & 0x0532) == 0x20)
			{
				if ((loc_8369 == 0) || ((loc_85b8 != 0x04) && (loc_85b8 != 0x03)))
				{
					loc_8369 = 0;
				}
				else
				{
					register unsigned char storedCmdDiByte = cmdDiBytes[0];
					if (loc_40030f & 0x10)
					{
						loc_8330 = 0x0800;
						loc_8332 = 0x0004;
						sub_83e13();
					}
					sub_83e03();
					loc_8368 &= 0xfe;
					if ((loc_8346 != 0x00) && (loc_8346 != 0x13))
					{
						loc_85b8 = 0x01;
					}
					else
					{
						loc_85b8 = 0x00;
					}
					loc_8369 = 0;
					sub_952b0(0x01, (void*)0xffdf);
					if (loc_838c != 0)
					{
						loc_838c = 0;
						sub_9241e();
					}
					if ((storedCmdDiByte == 0xa8) ||
						(storedCmdDiByte == 0xd0) ||
						(storedCmdDiByte == 0xa4))
					{
						sub_838dc();	// this is dmaXferToWii 99% sure
						if (loc_8368 & 0x10)
						{
							loc_8368 &= 0xffef;
							sub_89e6c();
						}
					}
					continue;
				}
			}
		}
		else
		{
			cmd0Flags = 0;
			asm("mov _cmd0Flags, a0");
			sub_94ec3(0x01, (void*)0xffff, 0x01);
			cmd0Flags |= 0x80;
		}

		if (((cmd0Flags & 0x44) == 0) || (loc_8346 != 0x81) || (aloc_85bc != 0x02)
			|| (ourSpeed & AFX_SWITCH))
		{
			cmd0Handler();
		}
		else
		{	// audiofix
		asm("
			jsr   _asub_85171
			jsr   _asub_851a5
			mov   8,d0
			mov   d0,(_aloc_85a8)
			mov   2,d0

			jsr   _asub_840b5
			mov   d0,(_aloc_837a)
			mov   5,d1
			mov   d1,(_aloc_85bc)
			mov   9,d2
			cmp   0,d0
			bne   label_afx1
			mov   2,d1
			mov   d1,(_aloc_85c6)
			mov   d2,(_aloc_85be)
			movb  d0,(_aloc_8373)

			mov   (_aloc_8418),a0
			mov   (6,a0),d2
			mov   (_aloc_8428),d3
			add   d2,d3
			sub   d1,d1

			add   -10,a3
			mov   d1,a2
			mov   1,d0
			movb  d0,(2,a3)
			mov   176,d2
			movb  d2,(1,a3)
			sub   d2,d2
			movb  d2,(a3)
			mov   a3,a0
			jsr   _asub_91e65
			movb  d2,(2,a3)
			movb  d2,(a3)
			mov   a3,a0
			mov   1,d0
			jsr   _asub_91e65
			mov   d3,(2,a3)
			mov   a2,d0
			mov   d0,(4,a3)
			mov   2,d0
			movb  d0,(1,a3)
			mov   8,d0
			movb  d0,(a3)
			mov   4,d0
			mov   a3,a0
			jsr   _asub_91e65
			add   10,a3

			sub   d2,d2
			bra   label_afx2

		label_afx1:
			mov   1,d0
			mov   d0,(_aloc_85c6)

		label_afx2:
			mov   d2,d0
			jsr   _asub_851aa
			jsr   _asub_8517e
		");
		}
	}
}

// libgcc doesnt include as it should
asm("
		.text
		.globl ___prologue
		.type ___prologue,@function
___prologue:
/* not needed, save code / stack size for audiofix ;-)
		mov (0,a3),a0
		add -16,a3
		movx d2,(4,a3)
		movx d3,(8,a3)
		mov a1,(12,a3)
		mov a2,(16,a3)
		mov a0,(0,a3)*/
		rts
		.size ___prologue,.-___prologue

		.text
		.globl ___epilogue_noreturn
		.type ___epilogue_noreturn,@function
___epilogue_noreturn:
/* not needed, save code / stack size for audiofix ;-)
		movx (0,a3),d2
		movx (4,a3),d3
		mov (8,a3),a1
		mov (12,a3),a2
		add 16,a3*/
		rts
		.size ___epilogue_noreturn,.-___epilogue_noreturn
");
